use sea_orm::{
    ConnectOptions, ConnectionTrait, Database, DatabaseConnection, DbBackend, Statement,
};
use std::cmp::max;
use std::time::Duration;

pub async fn init() -> anyhow::Result<DatabaseConnection> {
    let database_config = super::config::get().database();
    let mut options = ConnectOptions::new(format!(
        "{}://{}:{}@{}:{}/{}",
        database_config.driver(),
        database_config.username(),
        database_config.password(),
        database_config.host(),
        database_config.port(),
        database_config.database()
    ));

    let cpus = num_cpus::get() as u32;
    options
        .min_connections(max(cpus * 4, 10))
        .max_connections(max(cpus * 8, 20))
        .connect_timeout(Duration::from_secs(10))
        .acquire_timeout(Duration::from_secs(30))
        .idle_timeout(Duration::from_secs(60))
        .max_lifetime(Duration::from_secs(60 * 60 * 24))
        .sqlx_logging(false)
        .set_schema_search_path(database_config.schema())
        .sqlx_logging(false);

    let connection = Database::connect(options).await?;

    connection.ping().await?;
    tracing::info!("database connected");

    log_database_version(&connection).await?;

    Ok(connection)
}

async fn log_database_version(connection: &DatabaseConnection) -> anyhow::Result<()> {
    let stmt = Statement::from_string(
        DbBackend::Postgres,
        "SELECT version() AS version".to_string(),
    );
    let res = connection
        .query_one_raw(stmt)
        .await?
        .ok_or_else(|| anyhow::anyhow!("database version query failed"))?;
    let version: String = res.try_get("", "version")?;
    tracing::info!("database version: {}", version);
    Ok(())
}
